package com.kakarote.bi.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;
import com.kakarote.bi.common.enums.LoginType;
import com.kakarote.bi.entity.VO.BiExportLogVO;
import com.kakarote.bi.entity.VO.BiImportLogVO;
import com.kakarote.bi.entity.VO.BiLoginLogVO;
import com.kakarote.bi.entity.VO.BiOperateLogVO;
import com.kakarote.bi.service.BiLogService;
import com.kakarote.common.log.enums.ApplyEnum;
import com.kakarote.common.log.enums.BehaviorEnum;
import com.kakarote.common.log.enums.OperateObjectEnum;
import com.kakarote.common.log.enums.OperateTypeEnum;
import com.kakarote.core.common.Result;
import com.kakarote.core.entity.BasePage;
import com.kakarote.core.feign.admin.entity.SimpleUser;
import com.kakarote.core.feign.crm.entity.BiOperateLogParams;
import com.kakarote.core.utils.BaseUtil;
import com.kakarote.core.utils.ExcelParseUtil;
import com.kakarote.core.utils.UserCacheUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: admin
 * @version: v1.0
 * @date:2023/8/15
 */
@RestController
@RequestMapping("biLog")
@Api(tags = "BI日志模块")
public class BiLogController {

    @Autowired
    private BiLogService biLogService;


    @PostMapping("queryApply")
    @ApiOperation("查询应用")
    public Result queryApply(@RequestParam(defaultValue = "1") String isModule) {
        ApplyEnum[] values = ApplyEnum.values();
        //排除的应用
        List<ApplyEnum> excludeList = new ArrayList<ApplyEnum>() {{
            add(ApplyEnum.ADMIN);
            add(ApplyEnum.CRM);
            add(ApplyEnum.JXC);
            add(ApplyEnum.PM);
            add(ApplyEnum.FS);
            add(ApplyEnum.NULL);
        }};
        List<JSONObject> data = new ArrayList<>();
        for (ApplyEnum value : values) {
            if (excludeList.contains(value) || value.getModule().equals(BooleanUtil.toBoolean(isModule))) {
                continue;
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", value.getRemarks());
            jsonObject.put("value", value.getType());
            data.add(jsonObject);
        }
        return Result.ok(data);
    }

    @PostMapping("queryOperateObject")
    @ApiOperation("查询操作对象")
    public Result queryOperateObject(@RequestParam("apply") Integer apply) {
        List<OperateObjectEnum> operateObjectList = OperateObjectEnum.getOperateObjectList(apply);
        List<JSONObject> data = new ArrayList<>();
        for (OperateObjectEnum value : operateObjectList) {
            if (OperateObjectEnum.NULL.equals(value)) {
                continue;
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", value.getRemarks());
            jsonObject.put("value", value.getType());
            data.add(jsonObject);
        }
        return Result.ok(data);
    }

    @PostMapping("queryBehavior")
    @ApiOperation("查询操作行为")
    public Result queryBehavior() {
        BehaviorEnum[] values = BehaviorEnum.values();
        List<JSONObject> data = new ArrayList<>();
        for (BehaviorEnum value : values) {
            if (value.getState() == 1) {
                continue;
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", value.getName());
            jsonObject.put("value", value.getType());
            data.add(jsonObject);
        }
        return Result.ok(data);
    }

    @ApiOperation("查询登录日志")
    @PostMapping("/queryLoginLogs")
    public Result queryLoginLogs(@RequestBody BiOperateLogParams biParams) {
        biParams.setType(OperateTypeEnum.LOGIN.getType());
        BasePage<BiOperateLogVO> biOperateLogVOBasePage = biLogService.queryOperationLogs(biParams);

        BasePage<BiLoginLogVO> loginLogVOBasePage = new BasePage<>(biOperateLogVOBasePage.getPageNumber(), biOperateLogVOBasePage.getPageSize(), biOperateLogVOBasePage.getTotalRow());
        loginLogVOBasePage.setList(extractedLoginLog(biOperateLogVOBasePage));
        return Result.ok(loginLogVOBasePage);
    }


    @ApiOperation("导出登录日志")
    @PostMapping("/exportLoginLog")
    public void exportLoginLog(@RequestBody BiOperateLogParams biParams) {
        biParams.setType(OperateTypeEnum.LOGIN.getType());
        biParams.setPageType(0);
        BasePage<BiOperateLogVO> biOperateLogVOBasePage = biLogService.queryOperationLogs(biParams);

        List<BiLoginLogVO> list = extractedLoginLog(biOperateLogVOBasePage);
        List<Map<String, Object>> recordList = list.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());

        List<ExcelParseUtil.ExcelDataEntity> headList = new ArrayList<>();
        headList.add(ExcelParseUtil.toEntity("loginUserName", "登录账号"));
        headList.add(ExcelParseUtil.toEntity("userName", "登录人"));
        headList.add(ExcelParseUtil.toEntity("deptName", "部门名称"));
        headList.add(ExcelParseUtil.toEntity("loginType", "登录方式"));
        headList.add(ExcelParseUtil.toEntity("clientIp", "IP地址"));
        headList.add(ExcelParseUtil.toEntity("os", "系统类型"));
        headList.add(ExcelParseUtil.toEntity("platform", "平台类型"));
        headList.add(ExcelParseUtil.toEntity("browser", "浏览器类型"));
        headList.add(ExcelParseUtil.toEntity("createTime", "登录时间"));
        headList.add(ExcelParseUtil.toEntity("errorMsg", "异常信息"));
        ExcelParseUtil.exportExcel(recordList, new ExcelParseUtil.ExcelParseService() {
            @Override
            public String getExcelName() {
                return "登录日志";
            }

            @Override
            public boolean isXlsx() {
                return true;
            }
        }, headList);
    }

    private static List<BiLoginLogVO> extractedLoginLog(BasePage<BiOperateLogVO> biOperateLogVOBasePage) {
        List<BiLoginLogVO> loginLogVOList = new ArrayList<>();

        for (BiOperateLogVO biOperateLogVO : biOperateLogVOBasePage.getList()) {
            Object operationObj = biOperateLogVO.getOperationObj();
            String loginType = "-";
            String loginUserName = "-";
            if (BaseUtil.isJSONArray(String.valueOf(operationObj))) {
                JSONArray objects = JSON.parseArray(String.valueOf(operationObj));
                if (!objects.isEmpty()) {
                    JSONObject jsonObject = objects.getJSONObject(0);

                    Object type = jsonObject.get("loginType");
                    if (type instanceof String) {
                        loginType = LoginType.valueOf(type.toString()).getName();
                    } else {
                        loginType = LoginType.valueOf(TypeUtils.castToInt(jsonObject.get("loginType")));
                    }
                    loginUserName = jsonObject.getString("username");
                }
            }
            SimpleUser simpleUser = UserCacheUtil.getSimpleUser(biOperateLogVO.getCreateUserId());
            BiLoginLogVO build = BiLoginLogVO.builder()
                    .userName(ObjectUtil.isEmpty(simpleUser) ? "-" : simpleUser.getRealname())
                    .deptName(ObjectUtil.isEmpty(simpleUser) ? "-" : simpleUser.getDeptName())
                    .errorMsg(ObjectUtil.isEmpty(simpleUser) ? biOperateLogVO.getOperationInfo() : "")
                    .clientIp(biOperateLogVO.getClientIp())
                    .createTime(biOperateLogVO.getCreateTime())
                    .os("-")
                    .platform("-")
                    .browser("-")
                    .loginType(loginType)
                    .loginUserName(loginUserName)
                    .build();
            UserAgent userAgent = UserAgentUtil.parse(biOperateLogVO.getEquipmentType());
            if (ObjectUtil.isNotEmpty(userAgent)) {
                build.setOs(userAgent.getOs().getName());
                build.setPlatform(userAgent.getPlatform().getName());
                build.setBrowser(userAgent.getBrowser().getName());
            }

            loginLogVOList.add(build);
        }
        return loginLogVOList;
    }

    @PostMapping("queryOperationLogs")
    @ApiOperation("查询操作日志")
    public Result queryOperationLogs(@RequestBody BiOperateLogParams biParams) {
        BasePage<BiOperateLogVO> biOperateLogVOBasePage = biLogService.queryOperationLogs(biParams);

        return Result.ok(biOperateLogVOBasePage);
    }

    @ApiOperation("导出操作日志")
    @PostMapping("/exportOperateLog")
    public void exportOperateLogExcel(@RequestBody BiOperateLogParams biParams) {
        biParams.setPageType(0);
        BasePage<BiOperateLogVO> biOperateLogVOBasePage = biLogService.queryOperationLogs(biParams);

        List<BiOperateLogVO> list = biOperateLogVOBasePage.getList();
        for (BiOperateLogVO biOperateLogVO : list) {
            if (BaseUtil.isJSONArray(biOperateLogVO.getOperationInfo())) {
                String join = JSONUtil.parseArray(biOperateLogVO.getOperationInfo()).join(",");
                biOperateLogVO.setOperationInfo(join);
            }
            if (BaseUtil.isJSON(String.valueOf(biOperateLogVO.getOperationObj()))) {
                String typeName = JSONUtil.parseObj(biOperateLogVO.getOperationObj()).getStr("typeName");
                biOperateLogVO.setOperationObj(typeName);
            }
        }

        List<Map<String, Object>> recordList = list.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());

        List<ExcelParseUtil.ExcelDataEntity> headList = new ArrayList<>();
        headList.add(ExcelParseUtil.toEntity("userName", "操作人"));
        headList.add(ExcelParseUtil.toEntity("createTime", "操作时间"));
        headList.add(ExcelParseUtil.toEntity("behaviorName", "操作行为"));
        headList.add(ExcelParseUtil.toEntity("moduleName", "操作对象"));
        headList.add(ExcelParseUtil.toEntity("operationObj", "操作数据"));
        headList.add(ExcelParseUtil.toEntity("clientIp", "IP地址"));
        headList.add(ExcelParseUtil.toEntity("operationInfo", "操作详情"));
        ExcelParseUtil.exportExcel(recordList, new ExcelParseUtil.ExcelParseService() {
            @Override
            public String getExcelName() {
                return "用户操作日志";
            }

            @Override
            public boolean isXlsx() {
                return true;
            }
        }, headList);

    }


    @PostMapping("queryImportLogs")
    @ApiOperation("查询导入操作日志")
    public Result queryImportLogs(@RequestBody BiOperateLogParams biParams) {
        biParams.setType(OperateTypeEnum.IMPORT.getType());
        BasePage<BiOperateLogVO> biOperateLogVOBasePage = biLogService.queryOperationLogs(biParams);

        List<BiImportLogVO> biImportLogVOList = getBiImportLogVOS(biOperateLogVOBasePage);

        BasePage<BiImportLogVO> loginLogVOBasePage = new BasePage<>(biOperateLogVOBasePage.getPageNumber(), biOperateLogVOBasePage.getPageSize(), biOperateLogVOBasePage.getTotalRow());
        loginLogVOBasePage.setList(biImportLogVOList);

        return Result.ok(loginLogVOBasePage);
    }

    private static List<BiImportLogVO> getBiImportLogVOS(BasePage<BiOperateLogVO> biOperateLogVOBasePage) {
        List<BiImportLogVO> biImportLogVOList = new ArrayList<>();

        for (BiOperateLogVO biOperateLogVO : biOperateLogVOBasePage.getList()) {
            cn.hutool.json.JSONObject obj = JSONUtil.parseObj(biOperateLogVO.getOperationObj());
            cn.hutool.json.JSONObject info = JSONUtil.parseObj(biOperateLogVO.getOperationInfo());

            BiImportLogVO importLogVO = BiImportLogVO.builder()
                    .userName(biOperateLogVO.getUserName())
                    .createTime(biOperateLogVO.getCreateTime())
                    .importData(obj.getStr("uploadData"))
                    .importType(obj.getInt("uploadType"))
                    .moduleName(obj.getStr("name"))
                    .importNum(info.getInt("count"))
                    .skipNum(info.getInt("skipNum"))
                    .failNum(info.getInt("errorSize"))
                    .updateNum(info.getInt("updateNum"))
                    .failData(info.getStr("errorFile"))
                    .build();
            biImportLogVOList.add(importLogVO);
        }
        return biImportLogVOList;
    }

    @PostMapping("queryExportLogs")
    @ApiOperation("查询导出操作日志")
    public Result queryExportLogs(@RequestBody BiOperateLogParams biParams) {
        biParams.setType(OperateTypeEnum.EXPORT.getType());
        BasePage<BiOperateLogVO> biOperateLogVOBasePage = biLogService.queryOperationLogs(biParams);

        List<BiExportLogVO> biImportLogVOList = getBiExportLogLogVOS(biOperateLogVOBasePage);

        BasePage<BiExportLogVO> loginLogVOBasePage = new BasePage<>(biOperateLogVOBasePage.getPageNumber(), biOperateLogVOBasePage.getPageSize(), biOperateLogVOBasePage.getTotalRow());
        loginLogVOBasePage.setList(biImportLogVOList);

        return Result.ok(loginLogVOBasePage);
    }

    private List<BiExportLogVO> getBiExportLogLogVOS(BasePage<BiOperateLogVO> biOperateLogVOBasePage) {
        List<BiExportLogVO> biImportLogVOList = new ArrayList<>();
        for (BiOperateLogVO biOperateLogVO : biOperateLogVOBasePage.getList()) {
            cn.hutool.json.JSONObject obj = JSONUtil.parseObj(biOperateLogVO.getOperationObj());
            BiExportLogVO importLogVO = BiExportLogVO.builder()
                    .userName(biOperateLogVO.getUserName())
                    .createTime(biOperateLogVO.getCreateTime())
                    .moduleName(obj.getStr("name"))
                    .exportData(obj.getStr("fileData"))
                    .exportNum(Integer.valueOf(biOperateLogVO.getOperationInfo()))
                    .build();
            biImportLogVOList.add(importLogVO);
        }
        return biImportLogVOList;
    }
}
